﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Community.DynamicsCrmWebResourceTool.Models
{
    internal class Settings
    {
        internal string BusinessServiceUrl { get; set; }
        internal string Username { get; set; }
        internal string Password { get; set; }
        internal string Domain { get; set; }
        internal string SelectedSolution { get; set; }

        internal string SettingsFileName { get; set; }
        internal string SettingsFilePath { get; set; }

        private List<FileMap> curentMappings = new List<FileMap>();

        private bool isLoaded;

        private XmlDocument xmlDoc;

        private List<FileMap> Mappings;

        /// <summary>
        /// Loads connection settings from XML file and returns True if all the details are found
        /// </summary>
        /// <returns></returns>
        internal bool LoadConnection()
        {
            LoadXml();

            XmlNode url = xmlDoc.SelectSingleNode("//Settings/Connection/BusinessServiceUrl");
            if (url != null)
            {
                BusinessServiceUrl = url.InnerText;
            }
            XmlNode username = xmlDoc.SelectSingleNode("//Settings/Connection/Username");
            if (username != null)
            {
                Username = username.InnerText;
            }
            XmlNode password = xmlDoc.SelectSingleNode("//Settings/Connection/Password");
            if (password != null)
            {
                Password = password.InnerText;
            }
            XmlNode domain = xmlDoc.SelectSingleNode("//Settings/Connection/Domain");
            if (domain != null)
            {
                Domain = domain.InnerText;
            }

            //We can ignore domain because online CRM will not have domain
            if (!string.IsNullOrEmpty(BusinessServiceUrl) && !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password))
            {
                return true;
            }

            return false;
        }

        internal void SaveConnection()
        {
            LoadXml();

            XmlNode url = xmlDoc.SelectSingleNode("//Settings/Connection/BusinessServiceUrl");
            if (url != null)
            {
                url.InnerText = BusinessServiceUrl;
            }
            XmlNode username = xmlDoc.SelectSingleNode("//Settings/Connection/Username");
            if (username != null)
            {
                username.InnerText = Username;
            }
            XmlNode password = xmlDoc.SelectSingleNode("//Settings/Connection/Password");
            if (password != null)
            {
                password.InnerText = Password;
            }
            XmlNode domain = xmlDoc.SelectSingleNode("//Settings/Connection/Domain");
            if (domain != null)
            {
                domain.InnerText = Domain;
            }

            xmlDoc.Save(SettingsFilePath + SettingsFileName);
        }

        private void LoadXml()
        {
            if (!SettingsFilePath.EndsWith("\\"))
            {
                SettingsFilePath = SettingsFilePath + "\\";
            }
            if (!SettingsFilePath.EndsWith("Dynamics CRM Tool\\"))
            {
                SettingsFilePath = SettingsFilePath + "Dynamics CRM Tool\\";
            }
            if (!File.Exists(SettingsFilePath + SettingsFileName))
            {
                if (!Directory.Exists(SettingsFilePath))
                {
                    Directory.CreateDirectory(SettingsFilePath);
                }
                StreamWriter sw = File.CreateText(SettingsFilePath + SettingsFileName);
                sw.WriteLineAsync(
                    "<Settings><Connection><BusinessServiceUrl></BusinessServiceUrl><Username></Username><Password></Password><Domain></Domain><SelectedSolution></SelectedSolution></Connection><Mappings></Mappings></Settings>");
                sw.Close();
                sw.Dispose();
            }

            xmlDoc = new XmlDocument();
            xmlDoc.Load(SettingsFilePath + SettingsFileName);
        }

        internal List<FileMap> LoadMappings(Guid solutionId)
        {
            curentMappings = new List<FileMap>();

            XmlNodeList mappings =
                xmlDoc.SelectNodes("//Settings/Mappings/Mapping[@SolutionId='" +
                                   solutionId.ToString().Replace("{", "").Replace("}", "") + "']");
            if (mappings != null && mappings.Count > 0)
            {
                for (int i = 0; i < mappings.Count; i++)
                {
                    curentMappings.Add(GetFileMapFromXml(mappings[i]));
                }
            }
            return curentMappings;
        }

        internal void AddOrUpdateMapping(FileMap map)
        {
            if (map != null)
            {
                map.XmlDoc = xmlDoc;
                map.Save();
            }
        }

        internal void SaveMapping()
        {
            if (curentMappings != null)
            {
                foreach (var fileMap in curentMappings)
                {
                    fileMap.XmlDoc = xmlDoc;
                    fileMap.Save();
                }

                xmlDoc.Save(SettingsFilePath + SettingsFileName);
            }
        }

        internal void AddFileIfNotFound(string selectedFileName, Guid solutionId)
        {
            if (curentMappings != null)
            {
                var x = curentMappings.Any(f => f.FileName == selectedFileName);
                if (x == false)
                {
                    curentMappings.Add(new FileMap() {FileName = selectedFileName, SolutionId = solutionId.ToString()});
                }
            }
        }

        internal void UpdateUploadDate(object filename, Guid solutionId, DateTime uploadDate)
        {
            var mapping = (from m in curentMappings
                where m.FileName.Equals(filename) && m.SolutionId == solutionId.ToString()
                select m).FirstOrDefault();
            if (mapping != null)
            {
                mapping.LastUpload = uploadDate;
            }
        }

        internal void UpdateWebResourceId(string filename, Guid solutionId, Guid webResourceId)
        {
            if (curentMappings != null)
            {
                var mapping = (from m in curentMappings
                    where m.FileName.Equals(filename) && m.SolutionId == solutionId.ToString()
                    select m).FirstOrDefault();
                if (mapping != null)
                {
                    mapping.WebResourceId = webResourceId;
                }
            }
        }

        internal void UpdatePublishDate(List<Guid> webResourcesToPublish, DateTime publishDate)
        {
            var mappings = curentMappings.FindAll(m => webResourcesToPublish.Contains(m.WebResourceId));

            if (mappings != null)
            {
                foreach (var mapping in mappings)
                {
                    mapping.LastPublish = publishDate;
                }
            }
        }

        internal FileMap GetWebResourceIdForMapping(string currentDocument)
        {
            XmlNodeList mappings =
                xmlDoc.SelectNodes("//Settings/Mappings/Mapping[@FileName='" + currentDocument + "']");
            if (mappings != null && mappings.Count > 0)
            {
                for (int i = 0; i < mappings.Count; i++)
                {
                    //TODO: Returns first one in the list. Problem????
                    return GetFileMapFromXml(mappings[i]);
                }
            }

            return null;
        }

        private FileMap GetFileMapFromXml(XmlNode mappingNode)
        {
            FileMap map = new FileMap();
            map.Id = Guid.Parse(mappingNode.Attributes["Id"].Value);
            map.FileName = mappingNode.Attributes["FileName"].Value;
            map.SolutionId = mappingNode.Attributes["SolutionId"].Value;
            map.LastPublish =
                DateTime.ParseExact(mappingNode.Attributes["LastPublish"].Value, "yyyy-MM-dd HH:mm:ss",
                    CultureInfo.InvariantCulture);
            map.LastUpload =
                DateTime.ParseExact(mappingNode.Attributes["LastUpload"].Value, "yyyy-MM-dd HH:mm:ss",
                    CultureInfo.InvariantCulture);
            map.WebResourceName = mappingNode.Attributes["WebResourceName"].Value;

            if (!string.IsNullOrEmpty(mappingNode.Attributes["WebResourceId"].Value))
            {
                map.WebResourceId = Guid.Parse(mappingNode.Attributes["WebResourceId"].Value);
            }

            return map;
        }
    }
}
